import { useContext, useImperativeHandle, useRef } from 'react';

import { useControllableValue } from 'ahooks';
import { Button } from 'antd';

import Action from '@/components/action';

import {
  ActionType,
  BetaSchemaForm,
  ProForm,
  ProFormItem,
  ProTable,
  ProTableProps
} from '@ant-design/pro-components';
import { EditOrReadOnlyContext } from '@ant-design/pro-form/es/BaseForm/EditOrReadOnlyContext';
import type { ProFormFieldItemProps } from '@ant-design/pro-form/es/typing';

interface ProFormTableProps<T extends Record<string, any>>
  extends ProFormFieldItemProps<InnerProps<T>> {
  fieldProps: InnerProps<T>;
}

/**
 * 类似与list组件，展示方式是表格
 */
const ProFormTable = <T extends Record<string, any>>({
  fieldProps,
  ...formItemProps
}: ProFormTableProps<T>) => {
  return (
    <ProFormItem {...formItemProps}>
      <FormTable {...fieldProps} />
    </ProFormItem>
  );
};
export default ProFormTable;
export interface ProFormTableAction<T extends Record<string, any>> extends ActionType {
  /**
   * 新增一条数据
   */
  addRow: (values: T) => void;
  /**
   * 删除一条数据
   */
  removeRow: (rows?: T[]) => void;
  /**
   * 更新一条数据
   */
  updateRow: (values: T) => void;
}
interface InnerProps<T extends Record<string, any>>
  extends Omit<ProTableProps<T, any, GlobalValueType>, 'actionRef'> {
  actionRef?: React.Ref<ProFormTableAction<T> | undefined>;
  value?: T[];
  readOnly?: boolean;
}

export const FormTable = <T extends Record<string, any>>({
  actionRef,
  rowKey = 'id',
  readOnly,
  ...props
}: InnerProps<T>) => {
  const modeContext = useContext(EditOrReadOnlyContext);
  const readonly = modeContext.mode === 'read' || readOnly;
  // 数据源
  const [dataSource, setDataSource] = useControllableValue<T[]>(props, {
    defaultValue: []
  });
  const tableActionRef = useRef<ActionType>();
  const proFormTableActionRef = useRef<ProFormTableAction<T>>();
  proFormTableActionRef.current = {
    ...tableActionRef.current!,
    addRow: (values: T) => {
      setDataSource([...dataSource, { ...values }]);
    },
    updateRow: (values: T) => {
      setDataSource(
        dataSource.map((item) =>
          // @ts-ignore
          item[rowKey] === values[rowKey] ? values : item
        )
      );
    },
    removeRow: (rows: T[] = []) => {
      const deleteKeys = rows.map((row) => {
        // @ts-ignore
        return row[rowKey];
      });
      setDataSource(
        dataSource.reduce<T[]>((prev, curr) => {
          // @ts-ignore
          if (!deleteKeys.includes(curr[rowKey])) {
            prev.push(curr);
          }
          return prev;
        }, [])
      );
    }
  };
  useImperativeHandle(actionRef, () => proFormTableActionRef.current);

  return (
    <ProTable
      size="small"
      dataSource={dataSource}
      search={false}
      options={false}
      pagination={false}
      tableAlertRender={false}
      scroll={{
        x: 'max-content'
      }}
      rowSelection={readonly ? undefined : {}}
      toolBarRender={(action, { selectedRowKeys, selectedRows }) => {
        if (readonly) {
          return [];
        }
        if (props.toolBarRender) {
          return props.toolBarRender(action, { selectedRowKeys, selectedRows });
        }
        const hasSelected = Number(selectedRowKeys?.length) > 0;
        return [
          <EditForm
            mode="add"
            columns={props.columns}
            onFinish={(values) => {
              proFormTableActionRef.current?.addRow(values);
            }}
          />,
          <Button
            danger
            disabled={!hasSelected}
            onClick={() => {
              proFormTableActionRef.current?.removeRow(selectedRows);
            }}
          >
            删除
          </Button>
        ];
      }}
      {...props}
      columns={props.columns?.concat([
        {
          title: '操作',
          valueType: 'option',
          fixed: 'right',
          align: 'center',
          render: (_, row, index, action) => {
            const options = [
              <EditForm
                initialValues={row}
                columns={props.columns}
                onFinish={() => {}}
                mode="read"
              />
            ];
            if (!readonly) {
              options.push(
                ...[
                  <EditForm
                    initialValues={row}
                    columns={props.columns}
                    onFinish={(values) => {
                      proFormTableActionRef.current?.updateRow(values);
                    }}
                    mode="edit"
                  />,
                  <Button
                    danger
                    onClick={() => {
                      proFormTableActionRef.current?.removeRow([row]);
                    }}
                    type="link"
                  >
                    删除
                  </Button>
                ]
              );
            }
            return <Action>{options}</Action>;
          }
        }
      ])}
      rowKey={rowKey}
      actionRef={tableActionRef}
    />
  );
};
/**
 * 编辑表单
 */
const EditForm = ({
  initialValues,
  columns,
  onFinish,
  mode
}: {
  initialValues?: any;
  columns: any;
  onFinish: (values: any) => any;
  mode: 'edit' | 'add' | 'read';
}) => {
  const [form] = ProForm.useForm();
  const title = mode === 'edit' ? '编辑' : mode === 'add' ? '新增' : '详情';
  return (
    <BetaSchemaForm
      layoutType="ModalForm"
      title={title}
      trigger={<Button type={mode === 'add' ? 'primary' : 'link'}>{title}</Button>}
      readonly={mode === 'read'}
      requiredMark={mode !== 'read'}
      form={form}
      onFinish={async (values: any) => {
        await onFinish(values);
        return true;
      }}
      onOpenChange={(open) => {
        if (!open) {
          form.resetFields();
        } else {
          form.setFieldsValue(initialValues);
        }
      }}
      columns={[
        ...columns,
        {
          hideInTable: true,
          hideInSearch: true,
          formItemProps: {
            hidden: true,
            noStyle: true
          },
          title: '隐藏key',
          dataIndex: 'id',
          initialValue: new Date().getTime()
        }
      ]}
    />
  );
};
